﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.DirectoryServices;
using System.Security.Principal;

namespace PSE.Framework.ErrorLogging
{
    public class EnvironmentCollector
    {
        protected virtual EnvironmentData CreateEnvironmentData()
        {
            return new EnvironmentData();
        }

        protected virtual string GetVersion()
        {
            return "-";
        }

        public virtual EnvironmentData Collect(Dictionary<string, object> extensionData)
        {
            EnvironmentData environmentData = null;

            try
            {
                environmentData = this.CreateEnvironmentData();

                environmentData.OperationalSystem = this.GetData<string>(() => Environment.OSVersion.VersionString, "OperationalSystem", environmentData);
                environmentData.SystemVersion = this.GetData<string>(() => this.GetVersion(), "SystemVersion", environmentData);

                environmentData.ProcessorModel = this.GetData<string>(() => (string)Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0", "ProcessorNameString", string.Empty), "ProcessorModel", environmentData);
                environmentData.ProcessorUsage = this.GetData<int>(() => (int)new System.Diagnostics.PerformanceCounter("Processor", "% Processor Time", "_Total").NextValue(), "ProcessorUsage", environmentData);

                Microsoft.VisualBasic.Devices.ComputerInfo compInfo = new Microsoft.VisualBasic.Devices.ComputerInfo();

                environmentData.TotalPhysicalMemory = this.GetData<long>(() => (long)compInfo.TotalPhysicalMemory, "TotalPhysicalMemory", environmentData);
                environmentData.TotalUsedPhysicalMemory = this.GetData<long>(() => (long)(compInfo.TotalPhysicalMemory - compInfo.AvailablePhysicalMemory), "TotalUsedPhysicalMemory", environmentData);
                environmentData.ProcessUsedPhysicalMemory = this.GetData<long>(() => Environment.WorkingSet, "ProcessUsedPhysicalMemory", environmentData);

                System.IO.DriveInfo driveInfo = new System.IO.DriveInfo(System.Windows.Forms.Application.StartupPath);

                environmentData.HardDiskSize = this.GetData<long>(() => driveInfo.TotalSize, "HardDiskSize", environmentData);
                environmentData.UsedHardDiskSpace = this.GetData<long>(() => driveInfo.TotalSize - driveInfo.TotalFreeSpace, "UsedHardDiskSpace", environmentData);

                environmentData.MachineName = this.GetData<string>(() => Environment.MachineName, "MachineName", environmentData);
                environmentData.UserName = this.GetData<string>(() => WindowsIdentity.GetCurrent().Name, "UserName", environmentData);
                environmentData.IsAdministrator = this.GetData<bool>(() => new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator), "IsAdministrator", environmentData);
            }
            catch (Exception ex)
            {
                environmentData = HandleException(environmentData, ex);
            }

            return environmentData;
        }

        protected T GetData<T>(Func<T> getDataDelegate, string variableName, EnvironmentData environmentData)
        {
            T ret = default(T);

            try
            {
                ret = getDataDelegate();
            }
            catch (Exception ex)
            {
                if (environmentData.Errors == null)
                    environmentData.Errors = new List<string>();

                Exception error = new Exception(string.Format("Error collecting environment variable '{0}'", variableName), ex);

                environmentData.Errors.Add(error.ToString());
            }

            return ret;
        }

        protected EnvironmentData HandleException(EnvironmentData environmentData, Exception ex)
        {
            if (environmentData == null)
                environmentData = new EnvironmentData();

            if (environmentData.Errors == null)
                environmentData.Errors = new List<string>();

            Exception error = new Exception("Error collecting environment variables", ex);

            environmentData.Errors.Add(error.ToString());

            return environmentData;
        }

        //private List<string> GetGroups(string domain, string user)
        //{
        //    WindowsIdentity identity = WindowsIdentity.GetCurrent();
        //    WindowsPrincipal principal = new WindowsPrincipal(identity);
        //    principal.IsInRole(WindowsBuiltInRole.Administrator); 

        //    List<string> ret = WindowsIdentity.GetCurrent().Groups.Translate(typeof(NTAccount)).ToList().ConvertAll(g => g.Value);

        //    ret = new List<string>();

        //    string LDAP = @"LDAP://" + domain;

        //    DirectoryEntry deRoot = new DirectoryEntry(LDAP);
        //    DirectorySearcher deSrch = new DirectorySearcher(deRoot, @"(&(objectClass=user)(objectCategory=person)(cn=" + user + @"))");

        //    foreach (SearchResult oRes in deSrch.FindAll())
        //    {
        //        foreach (string propName in oRes.Properties.PropertyNames)
        //        {
        //            foreach (object value in oRes.Properties[propName])
        //            {
        //                ret.Add(propName + ": " + Convert.ToString(value));
        //            }
        //        }

        //        //Nome
        //        //oRes.Properties("cn")(0).ToString()
        //        //usuario
        //        //oRes.Properties("sAMAccountName")(0).ToString()

        //        //oRes.Properties("mail")(0).ToString()
        //    }

        //    return ret;
        //}

        //private List<string> Groups(string userDn, bool recursive)
        //{
        //    List<string> groupMemberships = new List<string>();

        //    return AttributeValuesMultiString("memberOf", userDn, groupMemberships, recursive);
        //}

        //private List<string> AttributeValuesMultiString(string attributeName, string objectDn, List<string> valuesCollection, bool recursive)
        //{
        //    using (DirectoryEntry ent = new DirectoryEntry(objectDn))
        //    {
        //        PropertyValueCollection ValueCollection = ent.Properties[attributeName];
        //        IEnumerator en = ValueCollection.GetEnumerator();

        //        while (en.MoveNext())
        //        {
        //            if (en.Current != null)
        //            {
        //                if (!valuesCollection.Contains(en.Current.ToString()))
        //                {
        //                    valuesCollection.Add(en.Current.ToString());
        //                    if (recursive)
        //                    {
        //                        AttributeValuesMultiString(attributeName, "LDAP://" + en.Current.ToString(), valuesCollection, true);
        //                    }
        //                }
        //            }
        //        }
        //    }

        //    return valuesCollection;
        //}
    }
}
